home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Commun⁄Network / NewsWatcher 2.0d17 Source / source / util.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-01  |  15.7 KB  |  657 lines  |  [TEXT/KAHL]

  1. /*----------------------------------------------------------------------------
  2.  
  3.     util.c
  4.  
  5.     This module contains miscellaneous utility routines.
  6.     
  7.     Portions copyright © 1990, Apple Computer.
  8.     Portions copyright © 1993, Northwestern University.
  9.  
  10. ----------------------------------------------------------------------------*/
  11.  
  12. #include <string.h>
  13. #include <Traps.h>
  14.  
  15. #include "glob.h"
  16. #include "util.h"
  17. #include "dlgutil.h"
  18. #include "mouse.h"
  19. #include "activate.h"
  20. #include "draw.h"
  21. #include "menus.h"
  22.  
  23.  
  24.  
  25. static CStr255 gStatusMsg;
  26. static OSErr gMemError = noErr;
  27.  
  28.  
  29.  
  30. /*    IsEqualFSSpec compares two canonical FSSpec records for equality.
  31. */
  32.  
  33. Boolean IsEqualFSSpec (FSSpec *file1, FSSpec *file2)
  34. {
  35.     return
  36.         file1->vRefNum == file2->vRefNum &&
  37.         file1->parID == file2->parID &&
  38.         EqualString(file1->name, file2->name, false, true);
  39. }
  40.  
  41.  
  42.  
  43. /*    GiveTime is called whenever the application is waiting for a slow
  44.     process to complete.  The routine calls SpinCursor and WaitNextEvent
  45.     to give time to currently running background applications.
  46. */
  47.  
  48. Boolean GiveTime (void)
  49. {
  50.     EventRecord ev;
  51.     Boolean gotEvt;
  52.     static long nextTime = 0;
  53.     char keyPressed, charPressed;
  54.     WindowPtr statusWind;
  55.     GrafPtr savePort;
  56.     ControlHandle cancel;
  57.     long myticks;
  58.     short part;
  59.     WindowPtr theWindow;
  60.  
  61.     HiliteMenu(0);
  62.     SetMenusTo(false, 0, 0, 0, 0, 0, 0);
  63.     ShowCursor();
  64.  
  65.     if (TickCount() >= nextTime) {
  66.             
  67.         SpinCursor(16);
  68.  
  69.         gotEvt = WaitNextEvent(everyEvent,&ev,0,nil);
  70.         
  71.         if ( gotEvt )
  72.             switch (ev.what) {
  73.                 case mouseDown:
  74.                     part = FindWindow(ev.where, &theWindow);
  75.                     if (part == inMenuBar) {
  76.                         MenuSelect(ev.where);
  77.                     } else if (IsStatusWindow(FrontWindow())) {
  78.                         HandleMouseDown(&ev);
  79.                     }
  80.                     break;
  81.                 case activateEvt:
  82.                     HandleActivate((WindowPtr)ev.message,
  83.                         ((ev.modifiers & activeFlag) != 0)); 
  84.                     break;
  85.                 case updateEvt:
  86.                     HandleUpdate((WindowPtr)(ev.message));
  87.                     break;
  88.                 case app4Evt:
  89.                     HandleSuspendResume(ev.message);
  90.                     break;
  91.                 case keyDown:
  92.                 case autoKey:
  93.                     FlushEvents(keyDownMask+keyUpMask+autoKeyMask,0);
  94.                     charPressed = ev.message & charCodeMask;
  95.                     keyPressed = (ev.message & keyCodeMask) >> 8;
  96.                     if (keyPressed == escapeKeyCode || 
  97.                         (ev.modifiers & cmdKey) != 0 && charPressed == '.') {
  98.                         statusWind = FrontWindow();
  99.                         if (IsStatusWindow(statusWind)) {
  100.                             cancel = ((WindowPeek)statusWind)->controlList;
  101.                             GetPort(&savePort);
  102.                             SetPort(statusWind);
  103.                             HiliteControl(cancel,1);
  104.                             Delay(8,&myticks);
  105.                             HiliteControl(cancel,0);
  106.                             SetPort(savePort);
  107.                         }
  108.                         gCancel = true;
  109.                     }
  110.                     break;
  111.             }
  112.         nextTime = TickCount() + 5;
  113.     }
  114.  
  115.     return !gCancel;
  116. }
  117.  
  118.  
  119. /*    StatusWindow displays a movable-modal status window indicating
  120.     the current state of the program.
  121. */
  122.  
  123. Boolean StatusWindow (char *text)
  124. {
  125.     WindowPtr statusWind;
  126.     Rect bounds = {0,0,75,420};
  127.     Rect buttonBounds = {42,347,62,407};
  128.     Rect msgBounds = {13, 13, 40, 420};
  129.     TWindow **info;
  130.     
  131.     if (!IsStatusWindow(statusWind = FrontWindow())) {
  132.         if (PtInRect(gPrefs.statusWindowLocn,&gDesktopExtent))
  133.             OffsetRect(&bounds,
  134.                 gPrefs.statusWindowLocn.h,
  135.                 gPrefs.statusWindowLocn.v);
  136.         else
  137.             OffsetRect(&bounds,100,100);
  138.         info = (TWindow**) MyNewHandle(sizeof(TWindow));
  139.         if (MyMemErr() != noErr)
  140.             return false;
  141.         strcpy(gStatusMsg,text);
  142.         (**info).kind = kStatus;
  143.         statusWind = NewWindow(nil, &bounds, "\pStatus", true,
  144.             movableDBoxProc, (WindowPtr)-1,
  145.             false, (unsigned long)info);
  146.         SetPort(statusWind);
  147.         NewControl(statusWind, &buttonBounds, "\pCancel", true, 0, 0, 0, 
  148.             pushButProc, 0);
  149.         ValidRect(&statusWind->portRect);
  150.         SpinCursor(0);
  151.     } else {
  152.         SetPort(statusWind);
  153.         strcpy(gStatusMsg,text);
  154.         EraseRect(&msgBounds);
  155.     }
  156.     TextFont(systemFont);
  157.     TextSize(12);
  158.     MoveTo(13,29);
  159.     DrawText(gStatusMsg,0,strlen(gStatusMsg));
  160.     return true;
  161. }
  162.  
  163.  
  164. /*    UpdateStatus is called in response to update events for the status
  165.     window.  This routine will redraw sections of the window as necessary.
  166. */
  167.  
  168. void UpdateStatus (void)
  169. {
  170.     GrafPtr savePort;
  171.     WindowPtr statusWind;
  172.     
  173.     statusWind = FrontWindow();
  174.     if (!IsStatusWindow(statusWind)) return;
  175.     GetPort(&savePort);
  176.     SetPort(statusWind);
  177.     EraseRect(&statusWind->portRect);
  178.     DrawControls(statusWind);
  179.     TextFont(systemFont);
  180.     TextSize(12);
  181.     MoveTo(13,29);
  182.     DrawText(gStatusMsg,0,strlen(gStatusMsg));
  183.     SetPort(savePort);
  184. }
  185.  
  186.  
  187. /*    CloseStatusWindow is called when the status window should be removed.
  188. */
  189.  
  190. void CloseStatusWindow (void)
  191. {
  192.     WindowPtr statusWind;
  193.     GrafPtr savePort;
  194.     TWindow **info;
  195.     
  196.     if (IsStatusWindow(statusWind = FrontWindow())) {
  197.         SetPt(&gPrefs.statusWindowLocn,0,0);
  198.         GetPort(&savePort);
  199.         SetPort(statusWind);
  200.         LocalToGlobal(&gPrefs.statusWindowLocn);
  201.         info = (TWindow**)GetWRefCon(statusWind);
  202.         SetPort(savePort);
  203.         MyDisposHandle((Handle)info );
  204.         DisposeWindow(statusWind);
  205.     }
  206. }
  207.  
  208. /*    MyIOCheck can be called to display the result of a routine returning
  209.     an OSErr.  If the value in err is zero, the routine simply terminates.
  210. */
  211.  
  212. OSErr MyIOCheck (OSErr err)
  213. {
  214.     if (err != noErr) {
  215.         UnexpectedErrorMessage(err);
  216.     }
  217.     return err;
  218. }
  219.  
  220.  
  221. /*    LowMemory is called when the program runs out of useable memory.
  222.     If this is the first time this has happened, the program de-allocates
  223.     lifeboat memory which was allocated when the program was launched.
  224.     Otherwise, the user had better quit.
  225. */
  226.  
  227. static Boolean LowMemory (void)
  228. {
  229.     Boolean result;
  230.     
  231.     if (MyMemErr() != memFullErr) {
  232.         MyIOCheck(MyMemErr());
  233.         return false;
  234.     }
  235.         
  236.     if (gSinking) {
  237.         result = false;
  238.         gOutOfMemory = true;
  239.         ErrorMessage("You have run out of memory");
  240.     }
  241.     else {
  242.         HUnlock(gLifeBoat);
  243.         DisposHandle(gLifeBoat);
  244.         gSinking = true;
  245.         result = true;
  246.         ErrorMessage("Memory is getting low.  Some operations may fail.");
  247.     }
  248.     return result;
  249. }
  250.  
  251.  
  252. /*    This is a wrapper for the NewPtr routine which automatically checks
  253.     the result of the call and takes appropriate action.
  254. */
  255.  
  256. Ptr MyNewPtr (Size byteCount)
  257. {
  258.     Ptr thePtr;
  259.     
  260.     thePtr = NewPtrClear(byteCount);
  261.     if ((gMemError = MemError()) != noErr) {
  262.         if (LowMemory())
  263.             thePtr = MyNewPtr(byteCount);
  264.         else
  265.             thePtr = nil;
  266.     }
  267.     return thePtr;
  268. }
  269.  
  270.  
  271. /*    This is a wrapper for the NewHandle routine which automatically checks
  272.     the result of the call and takes appropriate action.
  273. */
  274.  
  275. Handle MyNewHandle (Size byteCount)
  276. {
  277.     Handle theHndl;
  278.     
  279.     theHndl = NewHandleClear(byteCount);
  280.     if ((gMemError = MemError()) != noErr) {
  281.         if (LowMemory())
  282.             theHndl = MyNewHandle(byteCount);
  283.         else
  284.             theHndl = nil;
  285.     }
  286.     return theHndl;
  287. }
  288.  
  289. /*    This is a wrapper for the SetHandleSize routine which automatically checks
  290.     the result of the call and takes appropriate action.
  291. */
  292.  
  293. void MySetHandleSize (Handle h, Size newSize)
  294. {
  295.     long oldSize;
  296.  
  297.     oldSize = GetHandleSize(h);
  298.     SetHandleSize(h,newSize);
  299.     if ((gMemError = MemError()) != noErr) {
  300.         if (LowMemory())
  301.             MySetHandleSize(h,newSize);
  302.     } else if (oldSize < newSize) {
  303.         memset(*h+oldSize, 0, newSize-oldSize);
  304.     }
  305. }
  306.  
  307.  
  308. /*    This is a wrapper for the HandToHand routine which automatically checks
  309.     the result of the call and takes appropriate action.
  310. */
  311.  
  312. OSErr MyHandToHand (Handle *theHndl)
  313. {
  314.     Handle oldHndl;
  315.     OSErr result;
  316.     
  317.     oldHndl = *theHndl;
  318.     result = gMemError = HandToHand(theHndl);
  319.     if (result != noErr) {
  320.         *theHndl = oldHndl;
  321.         if (LowMemory())
  322.             result = MyHandToHand(theHndl);
  323.     }
  324.     return result;
  325. }
  326.  
  327.  
  328. /*    This is a wrapper for the DisposPtr routine which automatically checks
  329.     the result of the call and takes appropriate action.
  330.     NT: extra errorchecking for stability incorporated
  331. */
  332.  
  333. OSErr MyDisposPtr (Ptr thePtr)
  334. {
  335.     if(thePtr != nil)
  336.     {
  337.         DisposPtr(thePtr);
  338.         gMemError = MemError();
  339.     }
  340.     else
  341.     {
  342.         gMemError = noErr;
  343.     }
  344.     return MyIOCheck(gMemError);
  345. }
  346.  
  347.  
  348. /*    This is a wrapper for the DisposHandle routine which automatically checks
  349.     the result of the call and takes appropriate action.
  350.     NT: extra errorchecking for stability incorporated
  351. */
  352.  
  353. OSErr MyDisposHandle (Handle theHndl)
  354. {
  355.     if(theHndl != nil)
  356.     {
  357.         DisposHandle(theHndl);
  358.         gMemError = MemError();
  359.     }
  360.     else
  361.     {
  362.         gMemError = noErr;
  363.     }
  364.     return MyIOCheck(gMemError);
  365. }
  366.  
  367.  
  368. /*    This is a wrapper for the MemError routine which automatically checks
  369.     the result of the call and takes appropriate action.
  370. */
  371.  
  372. OSErr MyMemErr (void)
  373. {
  374.     return gMemError;
  375. }
  376.  
  377.  
  378. /*    IsAppWindow returns true if the window belongs to the application
  379. */
  380.  
  381. Boolean IsAppWindow (WindowPtr wind)
  382. {
  383.     short        windowKind;
  384.     
  385.     if (wind == nil)
  386.         return false;
  387.     else {
  388.         windowKind = ((WindowPeek)wind)->windowKind;
  389.         return windowKind >= userKind;
  390.     }
  391. }
  392.  
  393.  
  394. /*    IsDAWindow returns true if the window is a DA window
  395. */
  396.  
  397. Boolean IsDAWindow (WindowPtr wind)
  398. {
  399.     if (wind == nil)
  400.         return false;
  401.     else    /* DA windows have negative windowKinds */
  402.         return ((WindowPeek) wind)->windowKind < 0;
  403. }
  404.  
  405.  
  406. /*    IsStatusWindow returns true if the window is the status window.
  407. */
  408.  
  409. Boolean IsStatusWindow (WindowPtr wind)
  410. {
  411.     TWindow **info;
  412.  
  413.     if (!IsAppWindow(wind)) return false;
  414.     info = (TWindow**)GetWRefCon(wind);
  415.     return (**info).kind==kStatus;
  416. }
  417.  
  418.  
  419. /*    pstrcpy copies Pascal format strings.
  420. */
  421.  
  422. void pstrcpy (StringPtr to, StringPtr from)
  423. {
  424.     BlockMove(from, to, *from+1);
  425. }
  426.  
  427.  
  428. /*    GetPixelDepth gets the pixel depth of the monitor with the 
  429.     maximum intersection with a given rectangle.
  430.     
  431.     Entry:    *r = rectangle in local coord system of current port.
  432.     
  433.     Exit:    function result = pixel depth.
  434. */
  435.  
  436. short GetPixelDepth (Rect *r)
  437. {
  438.     Rect tempRect;
  439.     GDHandle theDev;
  440.     PixMapHandle theMap;
  441.     
  442.     if (!gHasColorQD) return 1;
  443.     tempRect = *r;
  444.     LocalToGlobal((Point*)&tempRect.top);
  445.     LocalToGlobal((Point*)&tempRect.bottom);
  446.     theDev = GetMaxDevice(&tempRect);
  447.     if (theDev == nil) return 1;
  448.     theMap = (**theDev).gdPMap;
  449.     if (theMap == nil) return 1;
  450.     return (**theMap).pixelSize;
  451. }
  452.  
  453. /*    VolNameToVRefNum returns a volume reference number given a volume name. */
  454.  
  455. OSErr VolNameToVRefNum (StringPtr name, short *vRefNum)
  456. {
  457.     HParamBlockRec pb;
  458.     Str31 volNameWithColon;
  459.     short len;
  460.     OSErr err;
  461.     
  462.     pstrcpy(volNameWithColon, name);
  463.     len = *volNameWithColon;
  464.     if (volNameWithColon[len] != ':') {
  465.         len = ++(*volNameWithColon);
  466.         volNameWithColon[len] = ':';
  467.     }
  468.     pb.volumeParam.ioNamePtr = volNameWithColon;
  469.     pb.volumeParam.ioVolIndex = -1;
  470.     err = PBHGetVInfo(&pb, false);
  471.     *vRefNum = pb.volumeParam.ioVRefNum;
  472.     return err;
  473. }
  474.  
  475.  
  476.  
  477. /*    GetFontNumber - Get font number corresponding to font name. 
  478.     Returns false if font does not exist. (From Think Ref) */
  479.  
  480.  
  481. Boolean GetFontNumber (Str255 fontName, short *fontNum)
  482. {
  483.     Str255 systemFontName;
  484.  
  485.     GetFNum(fontName, fontNum);
  486.     if (*fontNum == 0) {
  487.         /* Either we didn't find the font, or we were looking for the system
  488.           * font. */
  489.         GetFontName(0, systemFontName);
  490.         return EqualString(fontName, systemFontName, false, false);
  491.     } else {
  492.         return true;
  493.     }
  494. }
  495.         
  496.  
  497.  
  498. /*    The InitCursorCtl, SpinCursor, strcasecmp and strncasecmp functions 
  499.     are missing in Think, so we include them here    */
  500.  
  501. Handle gAcur = nil;
  502.  
  503. pascal void InitCursorCtl (Handle id)
  504. {
  505.     short NoFrames, i, CursId;
  506.     CursHandle    TheCursHndl;
  507.  
  508.     if (id == nil) {
  509.         gAcur = (Handle) GetResource('acur',0);
  510.         if(gAcur == nil) return;
  511.         HLock(gAcur);
  512.         NoFrames = ((short *)(*gAcur))[0];
  513.         for(i = 0; i < NoFrames; i++) {
  514.             CursId = ((short *)(*gAcur))[(2*i)+2];
  515.             TheCursHndl = GetCursor(CursId);
  516.             ((CursHandle *)(*gAcur))[i+1] = TheCursHndl;
  517.             HLock((Handle)TheCursHndl);
  518.         }
  519.     } else {
  520.         gAcur = id;
  521.         HLock(gAcur);
  522.         NoFrames = ((short *)(*gAcur))[0];
  523.         for(i = 0; i < NoFrames; i++) {
  524.             CursId = ((short *)(*gAcur))[(2*i)+2];
  525.             TheCursHndl = GetCursor(CursId);
  526.             ((CursHandle *)(*gAcur))[i+1] = TheCursHndl;
  527.             HLock((Handle)TheCursHndl);
  528.         }
  529.     }
  530.     ((short *)(*gAcur))[1] = 0;
  531.     DetachResource(gAcur);
  532. }
  533.  
  534.  
  535. pascal void SpinCursor (short num)
  536. {
  537.     short    NoFrames, CurrentFrame, CurrentCounter;
  538.     Cursor    CurrentCursor;
  539.  
  540.     if (gAcur == nil) InitCursorCtl(nil);
  541.     NoFrames = ((short *)(*gAcur))[0];
  542.     CurrentCounter = ((((short *)(*gAcur))[1] + num) % (NoFrames * 32));
  543.     ((short *)(*gAcur))[1] = CurrentCounter;
  544.     CurrentFrame = CurrentCounter / 32;
  545.     CurrentCursor = **(((CursHandle *)(*gAcur))[CurrentFrame+1]);
  546.     SetCursor(&CurrentCursor);
  547. }
  548.  
  549.  
  550. /*
  551.  * Copyright (c) 1987 Regents of the University of California.
  552.  * All rights reserved.
  553.  *
  554.  * Redistribution and use in source and binary forms are permitted
  555.  * provided that this notice is preserved and that due credit is given
  556.  * to the University of California at Berkeley. The name of the University
  557.  * may not be used to endorse or promote products derived from this
  558.  * software without specific written prior permission. This software
  559.  * is provided ``as is'' without express or implied warranty.
  560.  */
  561.  
  562. #ifndef u_char
  563.     #define u_char  unsigned char
  564. #endif
  565.  
  566. /*
  567.  * This array is designed for mapping upper and lower case letter
  568.  * together for a case independent comparison.  The mappings are
  569.  * based upon ascii character sequences.
  570.  */
  571. static u_char charmap[] = {
  572.     '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
  573.     '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
  574.     '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
  575.     '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
  576.     '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
  577.     '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
  578.     '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
  579.     '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
  580.     '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
  581.     '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
  582.     '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
  583.     '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
  584.     '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
  585.     '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
  586.     '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
  587.     '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
  588.     '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
  589.     '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
  590.     '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
  591.     '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
  592.     '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
  593.     '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
  594.     '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
  595.     '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
  596.     '\300', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
  597.     '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
  598.     '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
  599.     '\370', '\371', '\372', '\333', '\334', '\335', '\336', '\337',
  600.     '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
  601.     '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
  602.     '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
  603.     '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
  604. };
  605.  
  606.  
  607. short strcasecmp (const char *s1, const char *s2)
  608. {
  609.     u_char            *cm = charmap;
  610.     const u_char    *us1 = (const u_char *)s1;
  611.     const u_char    *us2 = (const u_char *)s2;
  612.  
  613.     while (cm[*us1] == cm[*us2++])
  614.         if (*us1++ == 0)
  615.             return(0);
  616.     return(cm[*us1] - cm[*--us2]);
  617. }
  618.  
  619.  
  620. short strncasecmp (const char *s1, const char *s2, short n)
  621. {
  622.     u_char            *cm = charmap;
  623.     const u_char    *us1 = (const u_char *)s1;
  624.     const u_char    *us2 = (const u_char *)s2;
  625.  
  626.     while (--n >= 0 && cm[*us1] == cm[*us2++])
  627.         if (*us1++ == 0)
  628.             return(0);
  629.     return(n < 0 ? 0 : cm[*us1] - cm[*--us2]);
  630. }
  631.  
  632. /*------------------------------------------------------------------------
  633.  * SetPortTextStyle
  634.  * Set the text font, size, style, etc. of the current port based
  635.  * on a TextStyle record.
  636.  * NOTE: color field is ignored for now.
  637.  */
  638. void SetPortTextStyle(const TextStyle *style)
  639. {
  640.     TextFont(style->tsFont);
  641.     TextFace(style->tsFace);
  642.     TextSize(style->tsSize);
  643. }
  644.  
  645. /*------------------------------------------------------------------------
  646.  * GetPortTextStyle
  647.  * Get the text font, size, style, etc. of the current port.
  648.  * NOTE: color field is ignored for now.
  649.  */
  650. void GetPortTextStyle(TextStyle *style)
  651. {
  652.     style->tsFont = qd.thePort->txFont;
  653.     style->tsFace = qd.thePort->txFont;
  654.     style->tsSize = qd.thePort->txFont;
  655. }
  656.  
  657.